using System;
using System.Collections.Generic;
using System.Text;
using GarageGames.Torque.T2D;
using GarageGames.Torque.Materials;
using GarageGames.Torque.Core;
using Microsoft.Xna.Framework;
using Xyne.Templates.PuzzlePieceTemplate;
using Xyne.Components;
using GarageGames.Torque.Sim;
using Microsoft.Xna.Framework.Input;
using GarageGames.Torque.Platform;
using Xyne.Actions;
using Xyne.Utilities;
using Microsoft.Xna.Framework.Net;
using Xyne.Objects;
using GarageGames.Torque.Lighting;
using GarageGames.Torque.GFX;

namespace Xyne.Regions
{
    class QueueRegionImpl : QueueRegion
    {
        private Queue<PlayerPieces> piecesQueue;
        private  Vector2 pieceOffset;

        private bool isWidescreen;

        private Random colorGenerator;
        private Vector2 queueOrigin;
        private Vector2 alignmentOrigin;
        private const int QueueSize = 10;

        public QueueRegionImpl(Rectangle inBounds) : base(inBounds)
        {

            colorGenerator = new Random(1);
        }

        #region Overrides
        public override void Init(PuzzleRegion puzzleRegion)
        {
            base.Init(puzzleRegion);
            isWidescreen = GFXDevice.IsWideScreen((int)Game.Instance.ClientBounds.X, (int)Game.Instance.ClientBounds.Y);
            ActionManager.Instance.Callbacks.Add(new ActionManager.ActionStateChangedDelegate(ActionStateChanged));

            piecesQueue = new Queue<PlayerPieces>();

            
            if (isWidescreen)
            {
                pieceOffset = new Vector2(0, PlayerPieces.Template.Size.Y);
                queueOrigin = new Vector2(Bounds.Left + (Bounds.Width / 2), Bounds.Bottom - 110f);
            }
            else
            {
                pieceOffset = new Vector2(PlayerPieces.Template.Size.Y, 0);
                queueOrigin = new Vector2(Bounds.Left + 110f, Bounds.Bottom - Bounds.Height / 2);
            }

            T2DSceneObject regionBackground = new T2DSceneObject();
            T2DStaticSprite background = new T2DStaticSprite();
            if (isWidescreen)
            {
                background.Size = new Vector2(Bounds.Width, Bounds.Height);
            }
            else
            {

                background.Size = new Vector2(Bounds.Height, Bounds.Width);
                background.Rotation = 90.0f;
            }

            background.Position = new Vector2(Bounds.Left + (Bounds.Width / 2), Bounds.Top + (Bounds.Height / 2));
            background.Layer = Game.BackgroundLayer;
            SimpleMaterial material = new SimpleMaterial();
            material.TextureFilename = @"data\images\QueueRegion.PNG";
            background.Material = material;
            TorqueObjectDatabase.Instance.Register(background);

            SetupAlignmentPieces();

            // Will make this dynamic later
            SpawnPiece();
            MovePieces();
            SpawnPiece();
            MovePieces();
            SpawnPiece();
            MovePieces();
            SpawnPiece();
            MovePieces();
            SpawnPiece();
            MovePieces();
            SpawnPiece();
            MovePieces();
            SpawnPiece();
            MovePieces();
            SpawnPiece();
            if (!isWidescreen)
            {
                MovePieces();
                SpawnPiece();
                MovePieces();
                SpawnPiece();
                MovePieces();
                SpawnPiece();
                MovePieces();
                SpawnPiece();
                MovePieces();
                SpawnPiece();
                MovePieces();
                SpawnPiece();
                MovePieces();
                SpawnPiece();
            }
        }


        public override PlayerPieces GetNextPiece()
        {
            PlayerPieces pieceToReturn = piecesQueue.Dequeue();
            MovePieces();
            SpawnPiece();
            return pieceToReturn;
        }

        public override void ModifyPlayerAlignment(AlignmentEnum alignment, float modfication)
        {
            base.ModifyPlayerAlignment(alignment, modfication);

            RefreshAlignmentSizes();
        }

        public override void ModifyEnemyAlignment(AlignmentEnum alignment, float modfication)
        {
            base.ModifyEnemyAlignment(alignment, modfication);

            RefreshAlignmentSizes();
        }
        #endregion

        #region Alignment Methods

        private void SetupAlignmentPieces()
        {
            alignmentOrigin = Vector2.Zero;
            //Vector2 alignmentSpriteOffset = new Vector2(Bounds.Width / ((int)AlignmentEnum.Length+1), 0);
            float rotationOffset = 360f / (float)AlignmentEnum.Length;
            for (int i = 0; i < (int)AlignmentEnum.Length; i++)
            {
                PuzzlePiece tempSprite = null;
                switch ((AlignmentEnum)i)
                {
                    case AlignmentEnum.Fire: tempSprite = PuzzlePiece.GetDisplayPuzzlePiece(PuzzlePieceColorEnum.Red); break;
                    case AlignmentEnum.Water: tempSprite = PuzzlePiece.GetDisplayPuzzlePiece(PuzzlePieceColorEnum.Blue); break;
                    case AlignmentEnum.Earth: tempSprite = PuzzlePiece.GetDisplayPuzzlePiece(PuzzlePieceColorEnum.Green); break;
                    case AlignmentEnum.Air: tempSprite = PuzzlePiece.GetDisplayPuzzlePiece(PuzzlePieceColorEnum.Yellow); break;
                    case AlignmentEnum.Light: tempSprite = PuzzlePiece.GetDisplayPuzzlePiece(PuzzlePieceColorEnum.White); break;
                    case AlignmentEnum.Dark: tempSprite = PuzzlePiece.GetDisplayPuzzlePiece(PuzzlePieceColorEnum.Black); break;
                }
                if (tempSprite != null)
                {
                    tempSprite.Name = GetAlignmentPieceName((AlignmentEnum)i);
                    if (alignmentOrigin == Vector2.Zero)
                    {
                        //alignmentSpriteOrigin = new Vector2(Bounds.X + tempSprite.Size.X / 2, Bounds.Bottom - tempSprite.Size.Y / 2);
                        if (isWidescreen)
                        {
                            alignmentOrigin = new Vector2(Bounds.X + Bounds.Width / 2, Bounds.Bottom - tempSprite.Size.Y * 1.2f);
                        }
                        else
                        {
                            alignmentOrigin = new Vector2(Bounds.X + tempSprite.Size.X * 1.2f, Bounds.Bottom - Bounds.Height/2 );
                        }
                        //tempSprite.Position = alignmentSpriteOrigin;
                    }
                    //else
                    //{
                        //tempSprite.Position = alignmentSpriteOrigin + alignmentSpriteOffset;
                    //    alignmentSpriteOffset += new Vector2(Bounds.Width / (int)AlignmentEnum.Length, 0);
                   // }
                    tempSprite.Position = alignmentOrigin + new Vector2(tempSprite.Size.X / 2 * (float)Math.Cos((double)MathHelper.ToRadians(rotationOffset * i)), tempSprite.Size.X / 2 * (float)Math.Sin((double)MathHelper.ToRadians(rotationOffset * i)));
                    tempSprite.InPlay = false;
                    TorqueObjectDatabase.Instance.Register(tempSprite);
                }
            }
        }

        private string GetAlignmentPieceName(AlignmentEnum alignment)
        {
            return "AlignmentPiece" + alignment.ToString();
        }

        private void RefreshAlignmentSizes()
        {
            float rotationOffset = 360f / (float)AlignmentEnum.Length;
            for (int i = 0; i < (int)AlignmentEnum.Length; i++)
            {
                PuzzlePiece piece = TorqueObjectDatabase.Instance.FindObject<PuzzlePiece>(GetAlignmentPieceName((AlignmentEnum)i));
                piece.Size = new Vector2(Game.PuzzlePieceWidth * PlayerAlignmentModifiers[i], Game.PuzzlePieceHeight * PlayerAlignmentModifiers[i]);

                piece.Position = alignmentOrigin + new Vector2(piece.Size.X / 2 * (float)Math.Cos((double)MathHelper.ToRadians(rotationOffset * i)), piece.Size.X / 2 * (float)Math.Sin((double)MathHelper.ToRadians(rotationOffset * i)));
            }
        }
        #endregion

        #region Spawning Pieces
        private void MovePieces()
        {
            foreach (PlayerPieces piece in piecesQueue)
            {
                if (isWidescreen)
                {
                    piece.WarpToPosition(piece.Position - pieceOffset, 0);
                }
                else
                {

                    piece.WarpToPosition(piece.Position + pieceOffset, 90.0f);
                }
                
            }
            return;
        }

        private void SpawnPiece()
        {
            PlayerPieces playerPieces = (PlayerPieces)PlayerPieces.Template.Clone();
            playerPieces.Position = queueOrigin;
            playerPieces.WorldLimit.MoveLimitMin = new Vector2(PuzzleRegion.Bounds.Left - 1, PuzzleRegion.Bounds.Top - 1);
            playerPieces.WorldLimit.MoveLimitMax = new Vector2(PuzzleRegion.Bounds.Right + 1, PuzzleRegion.Bounds.Bottom);
            playerPieces.CollisionsEnabled = false ;
            PuzzleMove puzzleMove = (PuzzleMove)CreateMoveComponent();
            playerPieces.Components.AddComponent(puzzleMove);
            TorqueObjectDatabase.Instance.Register(playerPieces);

            Random random = new Random(DateTime.Now.Second);

            PuzzlePiece first = (PuzzlePiece)PuzzlePiece.Template.Clone();

            first.Visible = true;
            first.WorldLimit.MoveLimitMin = new Vector2(PuzzleRegion.Bounds.Left - 1, PuzzleRegion.Bounds.Top - 1);
            first.WorldLimit.MoveLimitMax = new Vector2(PuzzleRegion.Bounds.Right + 1, PuzzleRegion.Bounds.Bottom);
            first.CollisionsEnabled = false;
            first.InPlay = false;
            first.SetPuzzlePieceColor(GetRandomColor());
            first.Components.AddComponent(new T2DLightComponent());
            TorqueObjectDatabase.Instance.Register(first);
            playerPieces.First = first;

            PuzzlePiece second = (PuzzlePiece)PuzzlePiece.Template.Clone();

            second.Visible = true;
            second.WorldLimit.MoveLimitMin = new Vector2(PuzzleRegion.Bounds.Left - 1, PuzzleRegion.Bounds.Top - 1);
            second.WorldLimit.MoveLimitMax = new Vector2(PuzzleRegion.Bounds.Right + 1, PuzzleRegion.Bounds.Bottom);
            second.CollisionsEnabled = false;
            second.InPlay = false;
            second.SetPuzzlePieceColor(GetRandomColor());
            second.Components.AddComponent(new T2DLightComponent());
            TorqueObjectDatabase.Instance.Register(second);
            playerPieces.Second = second;
            if (!isWidescreen)
            {
                playerPieces.Rotation = 90.0f;
            } 
            piecesQueue.Enqueue(playerPieces);
        }

        private PuzzlePieceColorEnum GetRandomColor()
        {
            float maxNumber = float.MinValue;
            PuzzlePieceColorEnum color = PuzzlePieceColorEnum.None;
            for (int i = 0; i < (int)AlignmentEnum.Length; i++)
            {
                float randomNumber = colorGenerator.Next(100) * PlayerAlignmentModifiers[i];
                if (maxNumber < randomNumber)
                {
                    switch ((AlignmentEnum)i)
                    {
                        case AlignmentEnum.Fire: color = PuzzlePieceColorEnum.Red; break;
                        case AlignmentEnum.Water: color = PuzzlePieceColorEnum.Blue; break;
                        case AlignmentEnum.Earth: color = PuzzlePieceColorEnum.Green; break;
                        case AlignmentEnum.Air: color = PuzzlePieceColorEnum.Yellow; break;
                        case AlignmentEnum.Light: color = PuzzlePieceColorEnum.White; break;
                        case AlignmentEnum.Dark: color = PuzzlePieceColorEnum.Black; break;
                    }
                    maxNumber = randomNumber;
                }
            }
            return color;
        }
        #endregion

        private TorqueComponent CreateMoveComponent()
        {
            // Move into controller utility at earliest convenience
            PuzzleMove move = new PuzzleMove();
            move.PuzzlePieceWidth = Game.PuzzlePieceWidth;

            return move;
        }

        private void ActionStateChanged(Action a)
        {
            switch (a.Type)
            {
                case ActionTypes.AlignmentChange:
                    AlignmentChangeAction action = a as AlignmentChangeAction;
                    foreach (GameObjects target in action.Targets)
                    {
                        if (target == Game.Network.Wizard)
                        {
                            foreach (AlignmentEnum alignment in action.Modifications.Keys)
                            {
                                ModifyPlayerAlignment(alignment, action.Modifications[alignment]);
                            }
                        }
                        if (target == (Game.Network.Wizard == GameObjects.LeftWizard ? GameObjects.RightWizard : GameObjects.LeftWizard))
                        {
                            foreach (AlignmentEnum alignment in action.Modifications.Keys)
                            {
                                ModifyEnemyAlignment(alignment, action.Modifications[alignment]);
                            }
                        }
                    }
                    break;
            }
        }

        /**
         * State string -> to be moved.
         * 
         * Player's alignment values (Black, Blue, Green, Red, White, Yellow)
         * Enemy's alignment values (Black, Blue, Green, Red, White, Yellow)
         **/
        public override void GetState(PacketWriter writer)
        {
            for (int i = 0; i < (int)AlignmentEnum.Length; i++)
            {
                writer.Write(EnemyAlignmentModifiers[i]);
            }

            for (int i = 0; i < (int)AlignmentEnum.Length; i++)
            {
                writer.Write(PlayerAlignmentModifiers[i]);
            }
        }

        public override void SetState(PacketReader reader)
        {
            for (int i = 0; i < (int)AlignmentEnum.Length; i++)
            {
                PlayerAlignmentModifiers[i] = reader.ReadSingle();
            }

            for (int i = 0; i < (int)AlignmentEnum.Length; i++)
            {
                EnemyAlignmentModifiers[i] = reader.ReadSingle();
            }
        }
    }
}
